<!--
Copyright 2014 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->

<script>
function NetworkSimulator(assert, done) {
  this._assert = assert;
  this._done = done;
  this._pendingPromises = [];
}

NetworkSimulator._testInProgress = false;

NetworkSimulator.prototype.schedulePromise = function(promise) {
  this._pendingPromises.push(promise);
  return promise;
};

NetworkSimulator.prototype.resolvePromises = function() {
  var self = this;
  return new Promise(function(resolve, reject) {
    var pendingPromises = self._pendingPromises;
    self._pendingPromises = [];
    function allResolved(results) {
      if (self._pendingPromises.length) {
        resolve(self.resolvePromises());
        return;
      }
      resolve(results);
    }
    Promise.all(pendingPromises).then(allResolved, allResolved);
  });
};

NetworkSimulator.prototype.runTest = function(testCase) {
  if (NetworkSimulator._testInProgress) {
    this._assert(false, "runTest calls cannot be nested");
    this._done();
    return;
  }

  NetworkSimulator._testInProgress = true;

  var self = this;
  var realNet = window.net;

  function reset() {
    window.net = realNet;
    NetworkSimulator._testInProgress = false;
  }

  return Promise.resolve().then(function() {
    // All net.* methods should return promises. This watches all
    // promises generated by test-overridden methods.
    window.net = {};
    ['probe', 'jsonp', 'get', 'post',
     'ajax', 'json', 'xml'].forEach(function(method) {
       if (method in self) {
         net[method] = function() {
           return self.schedulePromise(self[method].apply(self, arguments));
         };
       };
     });
  }).then(function() {
    return testCase();
  }).catch(function(e) {
    // Make sure errors thrown in the test case don't leave window.net in a bad state.
    reset();
    throw e;
  }).then(function() {
    return self.resolvePromises().then(function() {
      reset();
      self._assert(window.net == realNet);
    }).catch(function(e) {
      reset();
      self._assert(false, "Failed to finish test:" + e);
    })
  }).then(this._done, this._done);
};
</script>
